title_text = "Case Study: Attack! Vectors & Surface"
text = '''
The Dark Overlord contacts your school and demands payment in Bitcoin - or else they'll release student information (or worse)! This sounds like the plot of a bad movie, but in 2017, this really happened to a school district in Columbia Falls, Montana. And although they may have been one of the first, they're not alone! In December of 2020, the FBI issued a warning that showed a nearly 30% increase in ransomware attacks against schools.\n
Remote-learning made schools even more vulnerable to cyber attacks. Shadowy criminal hacker groups terrorized schools by hacking into school networks and demanding huge ransom payments, threatening terrible consequences if they weren't paid. In 2021, hackers demanded $40 million from a Florida school district. After the district offered to pay a smaller amount instead, the hackers published thousands of the district's stolen files. How do schools become victims of ransomware attacks? Hackers use attack vectors against the attack surface!\n
An attack vector is a way of gaining unauthorized access to a network or computer system. When hackers "hack into" a device or network, they use an attack vector. Attack vectors include weak passwords, out-of-date software, and links or files that download malicious (harmful) code. The attack surface is ALL of the attack vectors that could be used. You can think of it as all the weak points in your system! Software (like Zoom or Microsoft Teams), computers, network devices, and even teachers and students are all part of the attack surface. Surprisingly, people are the largest attack surface, and the weakest link! People can be tricked into visiting dangerous sites, running code, or sharing login information. This can give hackers access.\n
What can you do to stop cybercriminals? You've already started! Learning about cybersecurity and digital citizenship will make you a stronger, smarter cyber consumer.
'''
# Questions and options dictionary
# FORMAT: "question text": (correct_answer_number, [list of answer options])
question_to_options = {
"Threatening to publish or destroy data unless a payment is received is called a:": (3, ["attack vector" ,"attack surface", "ransomware attack", "publishing attack"]),
"The FBI reported that there was a nearly ______ in this type of attack against schools.": (3, ["10%", "20%", "30%", "70%"]),
"What is the definition of an attack vector?": (4, ["all the weak points in a computer/networking system", "hacker groups such as The Dark Overlord", "malicious code", "a way of gaining unauthorized access to a network or computer system"]),
"What is the attack surface?": (1, ["all the weak points in a computer/networking system", "hacker groups such as The Dark Overlord", "malicious code", "a way of gaining unauthorized access to a network or computer system"]),
"Which is the largest, weakest part of the attack surface?": (3, ["All computers in a network", "Outdated software on a computer", "People", "Weak passwords"])
}
#############################################################################################################
#############################################################################################################
############################ DO NOT EDIT BELOW CODE ############################
#############################################################################################################
#############################################################################################################
import codesters
import random
from codesters.demo import Demo
from codesters import Text
# SCROLL BUTTON EVENTS
def mouse_out(sprite):
for s in scroll_sprites:
s.set_y_speed(0)
sprite.set_outline_color("black")
def click_up(sprite):
for s in scroll_sprites:
s.set_y_speed(0)
sprite.set_outline_color("black")
def mouse_over(sprite):
# Disable scroll up
if title.get_top() < 251:
up_button.event_click(None)
for s in scroll_sprites:
s.set_y_speed(0)
# up_button.set_outline_color("black")
# Enable scroll up
if title.get_top() > 251:
up_button.event_click(up_click)
# Disable scroll down
if text_sprite.get_bottom()-500 > -225:
down_button.event_click(None)
for s in scroll_sprites:
s.set_y_speed(0)
# down_button.set_outline_color("black")
# Enable scroll down
if text_sprite.get_bottom()-500 < -225:
down_button.event_click(down_click)
def up_click(sprite):
up_button.set_outline_color("orange")
for s in scroll_sprites:
s.set_y_speed(-scroll_speed)
def down_click(sprite):
down_button.set_outline_color("orange")
for s in scroll_sprites:
s.set_y_speed(scroll_speed)
# ARROW KEY EVENTS
def up_arrow():
if text_sprite.get_top() < 199:
for s in scroll_sprites:
s.set_y_speed(0)
def down_arrow():
if text_sprite.get_bottom()-500 > -225:
for s in scroll_sprites:
s.set_y_speed(0)
def up_arrow_press():
up_button.set_outline_color("orange")
for s in scroll_sprites:
s.set_y_speed(-scroll_speed)
def up_arrow_release():
for s in scroll_sprites:
s.set_y_speed(0)
up_button.set_outline_color("black")
def down_arrow_press():
down_button.set_outline_color("orange")
for s in scroll_sprites:
s.set_y_speed(scroll_speed)
def down_arrow_release():
for s in scroll_sprites:
s.set_y_speed(0)
down_button.set_outline_color("black")
# INTERVAL EVENT TO LIMIT SCROLLING
def scroll_limiter():
# Disable scroll up
if title.get_top() < 251:
up_button.event_click(None)
for s in scroll_sprites:
s.set_y_speed(0)
# up_button.set_opacity(.5)
up_button.set_outline_color("black")
# Enable scroll up
if title.get_top() > 251:
# up_button.set_opacity(1)
up_button.event_click(up_click)
# Disable scroll down
if text_sprite.get_bottom()-500 > -225:
down_button.event_click(None)
for s in scroll_sprites:
s.set_y_speed(0)
down_button.set_outline_color("black")
# Enable scroll down
if text_sprite.get_bottom()-500 < -225:
down_button.event_click(down_click)
def stop_scrolling():
for s in scroll_sprites:
s.set_y_speed(0)
def disable_events():
stop_scrolling()
stage.remove_all_events()
stage.remove_all_sprite_events()
def enable_events():
# Stage button event handlers
up_button.event_click(up_click)
up_button.event_click_up(click_up)
down_button.event_click(down_click)
down_button.event_click_up(click_up)
up_button.event_mouse_over(mouse_over)
up_button.event_mouse_out(mouse_out)
down_button.event_mouse_over(mouse_over)
down_button.event_mouse_out(mouse_out)
# Up arrow key event handlers
stage.event_key("up", up_arrow)
stage.event_key_press("up", up_arrow_press)
stage.event_key_release("up", up_arrow_release)
# Down arrow key event handlers
stage.event_key("down", down_arrow)
stage.event_key_press("down", down_arrow_press)
stage.event_key_release("down", down_arrow_release)
# Scroll limiting interval event handler
stage.event_interval(scroll_limiter, .1)
def make_option_labels(button_list):
alpha = "ABCDEF"
label_list = []
for i, b in enumerate(button_list):
label = codesters.Text(alpha[i]+")", -260, b.get_y())
label.set_text_align("left")
label_list.append(label)
return label_list
def make_options(option_list):
text_list = []
for o in option_list:
option = Text(o, 0, offstage_below, "black")
option.set_text_width(450)
text_list.append(option)
return text_list
def make_buttons(num_options):
button_colors = ["lightblue", "orange", "thistle", "lightyellow", "lightseagreen", "lightgreen"]
button_list = []
for i in range(num_options):
button = codesters.Rectangle(0, offstage_below, 530, 30, button_colors[i], "black")
button.number = i+1
button_list.append(button)
return button_list
# Sets up question object with buttons, options, and labels
def make_question(question, option_list):
# First, remove any existing question
if question_sprites:
demo.remove_sprites(question_sprites)
for q in question_sprites:
scroll_sprites.remove(q)
# Most sprites created offstage and then moved to position
question_back = codesters.Rectangle(0, offstage_below, 540, 250, "white", "black")
question_text = codesters.Text(question, 0, offstage_below)
question_text.set_top(text_sprite.get_bottom()-50)
question_text.set_text_width(530)
# Create question components
button_sprites = make_buttons(len(option_list))
option_sprites = make_options(option_list)
# Store the bottom of the object above to place objects below it
spacing_under_question_text = 25
above_bottom = question_text.get_bottom()-spacing_under_question_text
# Place buttons and add option and option_label
button_spacing = 5
for i, b in enumerate(button_sprites):
b.set_height(option_sprites[i].get_height()+10)
b.set_top(above_bottom-button_spacing)
demo.add_hover_opacity_element(b)
option_sprites[i].go_to(b.get_x(), b.get_y())
above_bottom = b.get_bottom()
# Resize the question background and reset its position
question_back.set_height((question_text.get_top()-above_bottom)+20)
question_back.set_top(question_text.get_top()+10)
# Add labels to each question
option_label_sprites = make_option_labels(button_sprites)
# Return list of question data (NOTE: some items are lists)
question_data = [question_back, question_text, button_sprites, option_sprites, option_label_sprites]
return question_data
def add_to_score_animation(is_correct, score_text):
if is_correct:
animation = codesters.Text("+1", score_text.get_x() + score_text.get_width()/2 + 50, score_text.get_y(), "green")
create_feedback(u"✓", "green")
else:
animation = codesters.Text("-1", score_text.get_x() + score_text.get_width()/2 + 50, score_text.get_y(), "red")
create_feedback(u"✕", "red")
animation.set_size(0.75)
animation.turn_right(360)
stage.wait(0.2)
stage.remove_sprite(animation)
def create_feedback(input, color):
text = codesters.Text(input, 0, question_back.get_y(), color)
opacity = 1
size = 20
for counter in range(20):
opacity -= .05
size += 20
text.set_opacity(opacity)
text.set_text_size(size)
stage.wait(0.0001)
stage.remove_sprite(text)
# OPTION CLICK EVENT
def option_click(sprite):
global user_answer
disable_events()
user_answer = sprite.number
demo.unpause()
def answer_questions():
global user_answer, question_sprites, scroll_sprites, question_back
correct_text.set_text("Correct: 0")
incorrect_text.set_text("Incorrect: 0")
question_number.set_text("")
user_answer = None
correct = 0
incorrect = 0
# Create each question
for i, question in enumerate(question_to_options):
question_number.set_text(str(i+1) + " / " + str(len(question_to_options)))
question_data = make_question(question, question_to_options[question][1])
question_sprites = [question_data[0], question_data[1]]+question_data[2]+question_data[3]+question_data[4]
question_back = question_data[0]
# Enable physics and add sprites to scroll list
for q in question_sprites:
q.set_physics_on()
scroll_sprites += question_sprites
enable_events()
button_list = question_data[2]
for button in button_list:
button.event_click(option_click)
demo.pause()
# Remove event from the buttons
for button in button_list:
button.event_click(None)
demo.remove_hover_opacity_element(button)
button.set_opacity(.5)
# Check if user answer is correct
user_correct = question_to_options[question][0] == user_answer
# Correct scenario
if user_correct:
correct += 1
correct_text.set_text("Correct: " + str(correct))
add_to_score_animation(True, correct_text)
stage.wait(1)
# Incorrect scenario
else:
incorrect += 1
incorrect_text.set_text("Incorrect: " + str(incorrect))
add_to_score_animation(False, incorrect_text)
stage.wait(1)
# ALl questions answered
disable_events()
for sprite in question_sprites:
sprite.hide()
if correct == 1:
feedback = codesters.Text("You got " + str(correct) + " question correct out of " + str(len(question_to_options)) + " questions in total.")
else:
feedback = codesters.Text("You got " + str(correct) + " questions correct out of " + str(len(question_to_options)) + " questions in total.")
# Test to see if the student gets every question correct. If not, they don't pass the lesson.
tester = TestManager()
if correct == len(question_to_options):
tester.display_success_message("Great job!")
text_array = demo.remind_student_to_submit(question_back.get_x() - 180, question_back.get_y() - 100, 25)
for counter in range(5):
for sprite in text_array:
sprite.set_opacity(.7)
stage.wait(0.2)
for sprite in text_array:
sprite.set_opacity(1)
stage.wait(0.2)
else:
tester.display_failure_message("Darn! Play again to get all questions correct!")
demo.play_again()
demo.remove_all_sprites_except([up_button, down_button]+scroll_sprites)
answer_questions()
# Constants
stage_width = float(stage.get_stage_width())
stage_height = float(stage.get_stage_height())
offstage_below = -1000 # Use as y value to create objects below the stage
# Activity settings
scroll_speed = 6
# Create Demo instance
demo = Demo()
stage.auto_cache_off()
stage.disable_all_walls()
# Create title
title = codesters.Text(title_text, 0, 0, "#00a8e1")
title.set_text_weight("bold")
title.set_text_width(700)
title.set_text_size(35)
title.set_top(250)
# Create main text
text_sprite = codesters.Text(text, 0, 0)
text_sprite.set_text_size(25)
text_sprite.set_text_width(600)
# text_sprite.set_text_align("left")
text_sprite.set_text_height(30)
text_sprite.set_top(200)
# Calculate document dimensions
document_top = title.get_top()
document_bottom = text_sprite.get_bottom() # NOTE: this is a hard limit and is not dynamic
document_height = document_top - document_bottom
# # # Create images
# image_sprites = []
# image_x = -425
# image_width = 200
# image_spacing = document_height / len(image_labels)
# image_start_y = document_top - image_spacing/2
# # Dynamically resize and space each image
# for image_label in image_labels:
# image = codesters.Sprite(image_label, image_x, image_start_y)
# if image.get_width() > image_width:
# while image.get_width() > image_width:
# image.set_size(.95)
# else:
# while image.get_width() < image_width:
# image.set_size(1.05)
# image_sprites.append(image)
# image_start_y -= image_spacing
image1 = demo.create_sprite_off_screen("ransomware", -420, 75, .6)
image2 = demo.create_sprite_off_screen("ransom_1d5", -425, -255, .5)
image3 = demo.create_sprite_off_screen("worm_a5e", -425, -465, 1.3)
image4 = demo.create_sprite_off_screen("stealthviris_f8b", -425, -665, 1.3)
image5 = demo.create_sprite_off_screen("spyware_599", -425, -865, 1.3)
image_sprites = [image1, image2, image3, image4, image5]
# Scroll up/down buttons
up_button = codesters.Triangle(450, 0, 100, "black")
up_button.set_line_thickness(5)
up_button.set_bottom(25)
down_button = codesters.Triangle(450, 0, 100, "black")
down_button.set_line_thickness(5)
down_button.set_top(-25)
down_button.set_rotation(180)
# Correct and question number displays
correct_text = codesters.Text("Correct: 0", -450, text_sprite.get_bottom()-150, "green")
correct_text.set_text_align("left")
incorrect_text = codesters.Text("Incorrect: 0", -450, text_sprite.get_bottom()-150-40, "red")
incorrect_text.set_text_align("left")
question_number = codesters.Text("", -450, text_sprite.get_bottom()-150+40)
question_number.set_text_align("left")
# Create Placeholder question
question_sprites = []
question_data = make_question("Click Here to Load Questions", [" ", " ", " ", " "])
question_sprites = [question_data[0], question_data[1]]+question_data[2]+question_data[3]+question_data[4]
question_back = question_data[0]
# Build list of sprites that must scroll
scroll_sprites = [title, text_sprite, correct_text, incorrect_text, question_number]+image_sprites+question_sprites
# Turn physics on, especially for text sprites
for sprite in scroll_sprites:
sprite.set_physics_on()
# Enable all events for first time
enable_events()
# Start answering questions by clicking
question_back.event_click(answer_questions)